#include <string.h>
#include "mem.h"
#include "redblockobject.h"

static void block_clear(RedObject *self)
{
	rarray_unref(RedBlock_Entries(self));
}

static void block_release(RedObject *self)
{
	block_clear(self);
	Red_RELEASE();
}

static void block_traverse(RedObject *self, tp_visit_fn_t visit, void *args)
{
	rarray_t *entries = RedBlock_Entries(self);
	for (int i = 0; i < rarray_count(*entries); i++)
	{
		RedBlockEntry *entry = rarray_item_at(*entries, i, RedBlockEntry);
		for (int j = 0; j < rarray_count(entry->e_types); j++)
			Red_VISIT(rarray_item_at(entry->e_types, i, RedObject));
	}
}

RedTypeObject RedType_Block =
{
	RedType_INIT("block", RedBlockObject, RedType_Object)

	.tp_clear		= block_clear,
	.tp_release		= block_release,
	.tp_traverse	= block_traverse,
};

static void unref_entry(void *entry)
{
	Red_UNREF(((RedBlockEntry *)entry)->e_name);
	rarray_unref(&(((RedBlockEntry *)entry)->e_types));
	RedMem_Free(entry);
}

static void unref_object(void *object)
{
	Red_UNREF(object);
}

RedObject *RedBlock_Create(void)
{
	RedObject *result = RedObject_Create(&RedType_Block, NULL);

	if (!result)
		return NULL;

	RedBlock_Finally(result) = -1;
	RedBlock_Generic(result) = -1;
	rarray_create(RedBlock_Entries(result), unref_entry);
	return result;
}

RedBlockEntry *RedBlock_Append(RedObject *self)
{
	RedBlockEntry *entry = RedMem_Alloc(sizeof(RedBlockEntry));

	if (!entry)
		return NULL;

	entry->e_pc = -1;
	rarray_create(&(entry->e_types), unref_object);
	rarray_append(RedBlock_Entries(self), entry);
	return entry;
}
